Ext.namespace("org.microsite");
Ext.namespace("org.microsite.util");

/**
 * Used for selecting microsite user in forms
 * @class org.microsite.util.ObjectSelector
 * @extends Ext.form.ComboBox
 * 
 * @param service (required) DWR service to call for listing users
 * @param fields (required) array of field definitions
 * @param selectedValue the initial value as objectID
 */
org.microsite.util.ObjectSelector = Ext.extend(Ext.form.ComboBox, {
    type : null,
    service : null,
    reader : null,
    selectedValue : null,
    
    valueField : 'id',
    displayField :'name',
    typeAhead : true,
    forceSelection : true,
    mode : 'local',
    editable : false,
    triggerAction : 'all',

    initComponent : function() {
        if (this.type) {
            var vh = org.microsite.util.ViewRegistry.views[this.type.prototype.getType()];
            this.service = vh.service.list;
            this.reader = new Ext.data.ObjectReader({id: 'id'}, vh.createRecord());
        }
        Ext.apply(this, {
	        store: new Ext.data.Store({
                proxy : new Ext.ux.data.DwrProxy({
                    apiActionToHandlerMap : {
                        read : {
                            dwrFunction : this.service,
                            getDwrArgsFunction : function(trans) {
                                return [];
                            }
                        }
                    }
                }),
                reader : this.reader,
                autoLoad: false
            })
        });
        
        org.microsite.util.ObjectSelector.superclass.initComponent.apply(this);
        
        this.store.load({
            callback: function() {
                this.setValue(this.selectedValue);
            },
            scope : this
        });
    }
});

org.microsite.util.ObjectSelectorWindow = Ext.extend(Ext.Window, {
    title : 'Select from the list',
    width : 500,
    height : 300,
    closable : true,
    modal : true,
    layout : 'fit',

    type : null,
    service : null,
    serviceParams : [],
    reader : null,
    selectedValue : null,
    columnConfig : [{
        header: 'Name',
        dataIndex: 'name'
    },{
        header: 'Description',
        dataIndex: 'description'
    }],
    
    lvList : null,
    btOk : null,
    btCancel : null,
    
    initComponent : function() {
        if (this.type) {
            var vh = org.microsite.util.ViewRegistry.views[this.type.prototype.getType()];
            if (!this.service) this.service = vh.service.list;
            if (!this.reader)  this.reader  = new Ext.data.ObjectReader({id: 'id'}, vh.createRecord());
        }

        var cc = [];
        for (var i = 0; i < this.columnConfig.length; i++) {
            cc.push(Ext.apply({}, this.columnConfig[i]));
        }
        
        this.lvList = new Ext.ListView({
            store: new Ext.data.Store({
                proxy : new Ext.ux.data.DwrProxy({
                    apiActionToHandlerMap : {
                        read : {
                            dwrFunction : this.service,
                            getDwrArgsFunction : function(trans) {
                                return this.serviceParams;
                            },
                            getDwrArgsScope : this
                        }
                    }
                }),
                reader : this.reader,
                autoLoad: false
            }),
            singleSelect: true,
		    emptyText: 'Nothing to display',
		    columns: cc
		});
        
        this.btOk = new Ext.Button({
            text : 'OK',
            handler : this.onOkClicked,
            scope : this,
            disabled : true
        });
        this.btCancel = new Ext.Button({
            text : 'Cancel',
            handler : this.onCancelClicked,
            scope : this
        });
        
        Ext.apply(this, {
            items : [{
                xtype : 'panel',
                layout : 'fit',
                border : false,
                items : this.lvList
            }],
            buttons : [this.btOk, this.btCancel]
        });

        org.microsite.util.ObjectSelectorWindow.superclass.initComponent.apply(this);
        
        this.lvList.store.load({
            callback: function() {
                var idx;
                for (var i = 0; i < this.lvList.all.elements; i++) {
                    if (this.lvList.store.getAt(this.lvList.all.elements[i].viewIndex).id == this.selectedValue) {
                        idx = i;
                        break;
                    }
                }
                if (idx) this.lvList.select(record);
            },
            scope : this
        });

        this.lvList.on('selectionchange', this.onListSelectionChange, this);
        this.addEvents({
            'change' : true
        });
    },
    
    onListSelectionChange : function(lv, selection) {
        this.btOk.setDisabled(selection.length == 0);
    },
    
    onOkClicked : function(btn, e) {
        this.fireEvent('change', this.lvList.getSelectedRecords());
        this.close();
    },
    
    onCancelClicked : function(btn, e) {
        this.close();
    }
});

org.microsite.util.ObjectListView = Ext.extend(Ext.ux.form.FieldPanel, {
    border : false,

    type : null,
    reader : null,
    service : null,
    serviceParams : [],

    columnConfig : [{
        header: 'Name',
        dataIndex: 'name'
    },{
        header: 'Description',
        dataIndex: 'description'
    }],
    
    lvList : null,
    btnAdd : null,
    btnRemove : null,
    
    local : true,
    dataStore : null,
    
    initComponent : function() {
        if (this.type) {
            var vh = org.microsite.util.ViewRegistry.views[this.type.prototype.getType()];
            if (!this.service) this.service = vh.service.list;
            if (!this.reader)  this.reader  = new Ext.data.ObjectReader({id: 'id'}, vh.createRecord());
        }

        if (this.local) {
            this.dataStore = new Ext.data.Store({
                reader : this.reader
            });
        } else {
            this.dataStore = new Ext.data.Store({
                proxy : new Ext.ux.data.DwrProxy({
                    apiActionToHandlerMap : {
                        read : {
                            dwrFunction : this.service,
                            getDwrArgsFunction : function(trans) {
                                return this.serviceParams;
                            },
                            getDwrArgsScope : this
                        }
                    }
                }),
                reader : this.reader,
                autoLoad: true
            });
        }
        
        var cc = [];
        for (var i = 0; i < this.columnConfig.length; i++) {
            cc.push(Ext.apply({}, this.columnConfig[i]));
        }
        
        this.lvList = new Ext.ListView({
            store: this.dataStore,
            multiSelect: true,
            emptyText: 'Nothing to display',
            columns: cc
        });
        
        this.btnAdd = new Ext.Button({
            iconCls : 'addicon',
            tooltip : 'Add new item',
            handler : this.onAddClicked,
            scope : this
        });
        this.btnRemove = new Ext.Button({
            iconCls : 'delicon',
            tooltip : 'Remove selected item',
            handler : this.onRemoveClicked,
            scope : this,
            disabled : true
        });
        var p = new Ext.Panel({
                xtype : 'panel',
                layout : 'border',
                height : this.height || 100,
                border : false,
                items : [{
                    xtype : 'panel',
                    region : 'center',
                    border : true,
                    layout : 'fit',
                    items : this.lvList
                },{
                    xtype : 'panel',
                    region : 'east',
                    border : false,
                    width : 25,
                    items : [this.btnAdd, this.btnRemove]
                }]
            });

        Ext.apply(this, {
            items : p
//            items : this.lvList,
//            bbar : ['->', this.btnAdd, this.btnRemove]
        });

        org.microsite.util.ObjectListView.superclass.initComponent.apply(this);
        
        this.lvList.on('selectionchange', this.onListSelectionChange, this);
    },
    
    getValue : function() {
        var v = [];
        this.dataStore.each(function(record) {
            v.push(record.data.id);
        });
        return v;
    },
    
    getRawValue : function() {
        var v = [];
        this.dataStore.each(function(record) {
            v.push(record.data.id);
        });
        return v;
    },

    onListSelectionChange : function(lv, selection) {
        this.btnRemove.setDisabled(selection.length == 0);
    },
    
    onAddClicked : function(btn, e) {
        var win = new org.microsite.util.ObjectSelectorWindow({
            type : this.type
        });
        win.on('change', function(records) {
            this.lvList.store.add(records);
        }, this);
        win.show();
    },
    
    onRemoveClicked : function(btn, e) {
        Ext.MessageBox.confirm("Removing from list", "Do you really want to remove selected elements?", function(btn) {
            if (btn == 'yes') {
                var r = this.lvList.getSelectedRecords();
                for (var i = 0; i < r.length; i++) {
                    this.lvList.store.remove(r[i]);
                }
            }
        }, this);
    }
});

org.microsite.util.AutoField = Ext.extend(Ext.form.ComboBox, {
    service : null,
    columnName : null,
    
    displayField :'name',
    mode : 'remote',
    triggerAction : 'all',
    hideTrigger : true,

    initComponent : function() {
        Ext.apply(this, {
            store: new Ext.data.Store({
                proxy : new Ext.ux.data.DwrProxy({
                    apiActionToHandlerMap : {
                        read : {
                            dwrFunction : this.service.autocomplete,
                            getDwrArgsFunction : function(trans) {
                                return [this.columnName, ''];
                            },
                            getDwrArgsScope : this
                        }
                    }
                }),
                reader : new Ext.data.StringReader({id: 'name'}, Ext.data.Record.create([{name: 'name'}])),
                autoLoad: false
            })
        });
        
        org.microsite.util.AutoField.superclass.initComponent.apply(this);
    }
});

org.microsite.util.ViewRegistry = {
    views : [],
    
    add : function(view) {
        this.views[view.type.prototype.getType()] = view;
    }
};

org.microsite.util.ViewHelper = function() {
    this.constructor.apply(this, arguments);
};

org.microsite.util.ViewHelper.prototype = {
    type : null,
    template : null,
    fields : null,
    service : null,
    editor : null,
    
    constructor : function(config) {
        Ext.apply(this, config);
    },
    
    getFetchMethods : function() {
        return [this.fetchServer, this.fetchHost, this.fetchAdmin];
    },
    
    fetchHost : function(tmp, cb) {
        if (tmp.host) {
            HostRemote.load(tmp.host, {
                callback : function(h) {
                    tmp.host = h.name + ' ('+ h.ip + ')';
                    if (cb != null) cb.call(this, tmp);
                },
                scope : this
            });
        } else if (cb != null) cb.call(this, tmp);
    },
    
    fetchAdmin : function(tmp, cb) {
        if (tmp.admin) {
            UserRemote.load(tmp.admin, {
                callback : function(u) {
                    tmp.admin = (u.domain ? u.domain + '/' + u.name : u.name) + ' (' + u.pwd + ')';
                    if (cb != null) cb.call(this, tmp);
                },
                scope : this
            });
        } else if (cb != null) cb.call(this, tmp);
    },
    
    fetchServer : function(tmp, cb) {
        if (tmp.server) {
            ServerRemote.load(tmp.server, {
                callback : function(s) {
                    this.fetchHost(s, function(s2) {
	                    tmp.server = s.name + '<br/>hosted on ' + s2.host;
	                    if (cb != null) cb.call(this, tmp);
                    });
                },
                scope : this
            });
        } else if (cb != null) cb.call(this, tmp);
    },
    
    fetchProject : function(tmp, cb) {
        if (tmp.project) {
            ProjectRemote.load(tmp.project, {
                callback : function(p) {
                    tmp.project = p.name + ' (' + p.description + ')';
                    if (cb != null) cb.call(this, tmp);
                },
                scope : this
            });
        } else if (cb != null) cb.call(this, tmp);
    },
    
    fetchDatabase : function(tmp, cb) {
        if (tmp.database) {
            DatabaseRemote.load(tmp.database, {
                callback : function(d) {
                    this.fetchServer(d, function(d2) {
	                    tmp.database = d.name + ' (' + d.description + ')<br/>in ' + d2.server;
	                    if (cb != null) cb.call(this, tmp);
                    });
                },
                scope : this
            });
        } else if (cb != null) cb.call(this, tmp);
    },
    
    fillDataRecursive : function(data, cb, scope, m) {
        var method = m.shift();
        
        if (method) {
            method.call(this, data, function(tmp) {
                this.fillDataRecursive.call(this, tmp, cb, scope, m);
            }, this);
        } else if (cb) {
            cb.call(scope, data);
        }
    },
    
    fillData : function(data, cb, scope) {
        var tmp = Ext.apply({}, data);
        var m = [].concat(this.getFetchMethods());
        
        this.fillDataRecursive(tmp, cb, scope, m);
    },
    
    createRecord : function() {
        return this.fields ? Ext.data.Record.create(this.fields) : null;
    },
    
    getChildTypes : function(data) {
        return [];
    }
};

Ext.TreeCombo = Ext.extend(Ext.form.ComboBox, {
    store : new Ext.data.SimpleStore({fields:[],data:[[]]}),
    editable : false,
    mode : 'local',
    triggerAction : 'all',
    displayField : 'name',
    valueField : 'id',
    tree : null,
    
    data : null,
    dataType : null,
    _pathList : null,
    
    initList : function() {
        this.tree.on('click', this.onNodeClick, this);
        this.list = new Ext.Panel({
            autoScroll : true,
            height : 200,
            floating : true,
            alignTo : function(el, pos) {
                this.setPagePosition(this.el.getAlignToXY(el, pos));
            },
            items : [this.tree]
        });
    },

    expand: function() {
        if (!this.list.rendered) {
            this.list.render(document.body);
            this.list.setWidth(this.el.getWidth());
            this.innerList = this.list.body;
            this.list.hide();
            if (this._pathList) {
                this._pathList.shift();
                var node = this.tree.getRootNode();
                node.expand(false, false, function() {
                    this.expandTypedPath(this._pathList, node);
                }, this);
            }
        }
        this.el.focus();
        Ext.TreeCombo.superclass.expand.apply(this, arguments);
    },

    doQuery: function(q, forceAll) {
        this.expand();
    },

    collapseIf : function(e){
        if(!e.within(this.wrap) && !e.within(this.list.el)){
            this.collapse();
        }
    },

    onNodeClick: function(node, e) {
        this.data = node.attributes.data;
        this.setRawValue(node.attributes.text);
        if (this.hiddenField) {
            this.hiddenField.value = node.attributes.data.id;
        }
        this.collapse();
    },
    
    getValue : function() {
        return this.data ? this.data.id : '';
    },
    
    expandTypedPath : function(list, node) {
        if (list.length == 0) {
            node.select();
        } else {
            var d = list.shift();
            var nd = node.findChildBy(function(n) {
                
                return n.attributes.data.id == this.id &&
                       n.attributes.data.getType() == this.getType();
            }, d);
            nd.expand(false, false, function() {
                this.expandTypedPath(list, nd);
            }, this);
        }
    },
    
    initComponent : function() {
        Ext.TreeCombo.superclass.initComponent.call(this);
        
        if (this.data && this.dataType) {
            var vh = org.microsite.util.ViewRegistry.views[this.dataType.prototype.getType()];
            vh.service.loadPath(this.data, {
                callback : function(list) {
                    this.setRawValue(list[list.length - 1].name);
                    this._pathList = list;
                },
                scope : this
            });
        }
    }
});
Ext.reg('treecombo', Ext.TreeCombo);


/**
 * Comet extension
 * 
 * usage:
 * var c = new Ext.Comet({url:"survey.php",interval:200});
 * c.on("receive", function(v) {
 *     // do something with v 
 * });
 * c.start();
 * 
 * Server side example (PHP):
 * $val = Array(5, "toto"); 
 * while (true) { 
 *     $val[0]++; 
 *     $val[1] .= "."; 
 *     sleep(rand(1,5)); 
 *     echo json_encode($val); 
 *     echo "\n"; 
 *     flush(); 
 * }
 * 
 * @param {} config
 */
Ext.Comet = function(config) {
    this.events = {
        receive:true
    }
    Ext.apply(this, config);
}
Ext.extend(Ext.Comet, Ext.util.Observable, {

    _intervalId : null,
    request : null,
    interval : 200,
    lastTextPosition: 0,
    autoReconnect : true,
    reconnectIntervalOnFailure : 5000,
    url : null,

    start : function() {
        this.request = Ext.Ajax.request({
            url:this.url,
            callback:this.requestCallback,
            scope:this
        });
        this._intervalId = setInterval(this.watch.createDelegate(this),
            this.interval);
    },

    requestCallback : function(o, success, r) {
        console.log("End :", o, success, r);
        this.watch();
        this.stop();
        if (this.autoReconnect) {
            if (success) {
                this.start();
            } else {
                this.start.defer(this.reconnectIntervalOnFailure, this);
            }
        }
    },

    watch : function() {
        var text = this.request.conn.responseText;
        if (text.length == this.lastTextPosition) { return; }
        var last = text.substring(this.lastTextPosition);
        this.lastTextPosition = text.length;
        var lasts = last.split("\\n");
        var nbInfos = lasts.length;
        for (i = 0; i < nbInfos; i++) {
            if (lasts[i] === "") { continue; }
/*            o = "";
            try {
                o = eval("("+lasts[i]+")");
                if (!o) { o = lasts[i]; }
            } catch(ex) {
                o = lasts[i];
            }
            this.fireEvent("receive", o);*/
            this.fireEvent("receive", lasts[i]);
        }
    },

    stop : function() {
        clearInterval(this._intervalId);
        this.request.conn.abort();
    }
});